#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using AbstractClass.Extensions;
using AbstractClass.Linq;

namespace AbstractClass.Collections.Generic
{
    /// <summary>
    /// Represents a strongly typed list with a fixed capacity.
    /// </summary>
    /// <typeparam name="T">The type of elements in the collection.</typeparam>
    [Serializable, DebuggerDisplay("Count = {Count}")]
    public class Pocket<T> : List<T>, IAlgorithmAware<Pocket<T>>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Pocket&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="capacity">The maximum number of element it can contain.</param>
        public Pocket(int capacity)
        {
            Capacity = capacity;
        }

        /// <summary>
        /// Gets or sets the capacity of the <see cref="Pocket&lt;T&gt;"/>.
        /// </summary>
        /// <value>The maximum number of element it can contain.</value>
        public new int Capacity { get; protected set; }

        /// <summary>
        /// Adds the specified item into <see cref="Pocket&lt;T&gt;"/>. If it exceeds the capacity 
        /// it will throw <see cref="PocketOverflowException"/>.
        /// </summary>
        /// <param name="item">The item to add.</param>
        /// <exception cref="PocketOverflowException"><see cref="Pocket&lt;T&gt;"/> size is already reached its capacity.</exception>
        public new void Add(T item)
        {
            if (Count == Capacity)
                throw new PocketOverflowException();
            base.Add(item);
        }

        /// <summary>
        /// Adds the elements of the specified collection to the end of the <see cref="Pocket&lt;T&gt;"/>.
        /// </summary>
        /// <param name="collection">The collection whose elements should be added to the end of the <see cref="Pocket&lt;T&gt;"/>.</param>
        /// <exception cref="PocketOverflowException"><see cref="Pocket&lt;T&gt;"/> size is already reached its capacity.</exception>
        public new void AddRange(IEnumerable<T> collection)
        {
            if (collection.IsNullOrEmpty())
                throw new ArgumentNullException("collection", LanguageResource.CollectionCanNotBeEmptyOrNull);

            foreach (T item in collection)
            {
                Add(item);
            }
        }

        /// <summary>
        /// Changes the capacity of the <see cref="Pocket&lt;T&gt;"/>.
        /// </summary>
        /// <param name="newCapacity">The new capacity of the <see cref="Pocket&lt;T&gt;"/>.</param>
        /// <param name="truncate">if set to <c>true</c> it removes the excess elements.</param>
        /// <exception cref="ArgumentException"><paramref name="truncate"/> is set to false and <paramref name="newCapacity"/> 
        /// is less than the old capacity.
        /// </exception>
        public void ReDim(int newCapacity, bool truncate)
        {
            if (!truncate && newCapacity < Capacity)
                throw new ArgumentException(LanguageResource.ValueMayBeTruncated);

            Capacity = newCapacity;
        }

        #region Implementation of IAlgorithmAware<out Pocket<T>>

        /// <summary>
        /// Executes the <paramref name="algorithm"/> on the <see cref="Pocket&lt;T&gt;"/>.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="algorithm">The algorithm to run on the <see cref="Pocket&lt;T&gt;"/>.</param>
        /// <returns>The result of execution of <paramref name="algorithm"/> on the <see cref="Pocket&lt;T&gt;"/>.</returns>
        public TResult ExecuteAlgorithm<TResult>(IAlgorithm<Pocket<T>, TResult> algorithm)
        {
            algorithm.ThrowIfNull("algorithm");
            return algorithm.Run(this);
        }

        #endregion
    }
}